package cn.wolfcode.wolf2w.service.impl;

import cn.wolfcode.wolf2w.cache.vo.CatalogVO;
import cn.wolfcode.wolf2w.cache.vo.StrategyStatisVO;
import cn.wolfcode.wolf2w.domain.*;
import cn.wolfcode.wolf2w.query.StrategyQuery;
import cn.wolfcode.wolf2w.repository.StrategyRepository;
import cn.wolfcode.wolf2w.service.IDestinationService;
import cn.wolfcode.wolf2w.service.IStrategyCatalogService;
import cn.wolfcode.wolf2w.service.IStrategyService;
import cn.wolfcode.wolf2w.service.IStrategyThemeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;

@Service
// @Transactional
public class StrategyServiceImpl implements IStrategyService{
    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private StrategyRepository strategyRepository;

    @Autowired
    private IStrategyCatalogService strategyCatalogService;

    @Autowired
    private IStrategyThemeService strategyThemeService;

    @Autowired
    private IDestinationService destinationService;

    @Override
    public void add(Strategy strategy) {
        strategy.setId(null);
        strategyRepository.save(strategy);
    }

    @Override
    public void delete(String id) {

        strategyRepository.deleteById(id);
    }

    @Override
    public void update(Strategy strategy) {
        // 当实现修改操作时,如果数据库列表中的字段和 domain里面的一致就
        // 不用先查后修改操作.
       /* String id = strategy.getId();
        Strategy newStrategy = mongoTemplate.findById(id, Strategy.class);*/
        strategyRepository.save(strategy);

    }

    @Override
    public Strategy get(String id) {

        return strategyRepository.findById(id).get();
    }

    @Override
    public List<Strategy> list() {

        return strategyRepository.findAll();
    }


    @Override
    public Page<Strategy> query(StrategyQuery qo) {
        // 创建查询对象
        Query query = new Query();


        // 查询数据总数
        long totalCount = mongoTemplate.count(query, Strategy.class);

        if (totalCount == 0){
            // 返回一个空白页面
            return Page.empty();
        }

        // 分页
        Pageable page = PageRequest.of(qo.getCurrentPage() - 1, qo.getPageSize(),
                Sort.Direction.ASC, "_id");

        // 给查询加入限制条件
        query.with(page);

        List<Strategy> list = mongoTemplate.find(query, Strategy.class);

        // 实现接口方法是调用分页插件page
        return new PageImpl<>(list,page,totalCount);
    }

    @Override
    public List<CatalogVO> groupList() {
        // 创建查询结果对象集
        List<CatalogVO> list = new ArrayList<>();
        //
        TypedAggregation<StrategyCatalog> agg = Aggregation.newAggregation(StrategyCatalog.class,
                // 以目的地名称作为分组对象的id
                Aggregation.group("destName").
                        // 对应将攻略名称加入names数组中
                        push("name").as("names").
                        // 对应将攻略id加入ids数组中
                        push("id").as("ids") );

        // 构建Map结构的数据类型
        AggregationResults<Map> result = mongoTemplate.aggregate(agg,Map.class);

        List<Map> datas = result.getMappedResults();
        // 遍历对应 以目的地名称作为分组对象集
        for (Map data : datas) {
            // 创建目的地与攻略对象关系的对象
            CatalogVO vo = new CatalogVO();
            // 给目的地与攻略对象关系的对象对应的destinationId属性设置
            vo.setDestinationId(data.get("_id").toString());
            // 给目的地与攻略对象关系的对象对应的属性设置
            List<Object> names = (List<Object>) data.get("names");
            // 给目的地与攻略对象关系的对象对应的属性设置
            List<Object> ids = (List<Object>) data.get("ids");
            // 创建一个攻略分类集合,用来存攻略分类对象
           List<StrategyCatalog> strategyCatalogs = new ArrayList<>();

            for (int i = 0;i < names.size(); i++) {
                // 创建攻略分类对象
                StrategyCatalog sc = new StrategyCatalog();
                // 获取攻略对象中的属性值
                String name = names.get(i).toString();
                String id = ids.get(i).toString();
                // 给攻略分类对象中的属性设置
                sc.setId(id);
                sc.setName(name);
                strategyCatalogs.add(sc);
            }
            // 给目的地与攻略对象关系的对象对应的catalogList属性设置
            vo.setCatalogList(strategyCatalogs);
            list.add(vo);
        }

        return list;
    }

    @Override
    public void changeState(int state, String id) {
        // 部分字段更新
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(id));
        // 由mongodb 提供的修改方法
        Update update = new Update(); // $set
        update.set("state",state);  // state = 1
        mongoTemplate.updateMulti(query,update,Strategy.class);

    }

    @Override
    public List<Strategy> queryCatalogId(String id) {
        List<Strategy> strategies =  strategyRepository.findByCatalogId(id);
        return strategies;
    }


    @Override
    public List<Strategy> queryStrategyByDestId(String destId) {
        //  通过目的地id查询对应的所有攻略明细
        List<Strategy> strategyList = strategyRepository.findByDestId(destId);
        return strategyList;
    }

    // vo对象更新的持久化操作
    @Override
    public void updateStrategyVo(StrategyStatisVO vo) {
        // 创建查询对象
        Query query = new Query();
        // 根据_id进行作为查询条件
        query.addCriteria(Criteria.where("_id").is(vo.getStrategyId()));
        // 适用于用于部分更新对象中的属性
        Update update = new Update();

        update.set("favornum",vo.getFavornum());
        update.set("replynum",vo.getReplynum());
        update.set("thumbsupnum",vo.getThumbsupnum());
        update.set("viewnum",vo.getViewnum());
        update.set("sharenum",vo.getSharenum());
        mongoTemplate.updateMulti(query,update,Strategy.class);
    }

    @Override
    public List<Strategy> queryByDestName(String keyword) {
        List<Strategy> strategyList = strategyRepository.findByDestName(keyword);
        return strategyList;
    }

    @Override
    public List<Strategy> queryStrategyById(List<String> sids) {
        // 查询id集合，返回攻略对象集合
        List<Strategy> strategies = strategyRepository.findByIdIn(sids);

        return strategies;
    }

    @Override
    public void saveOrUpdate(Strategy strategy) {

        // 目的地id
        String catalogId = strategy.getCatalogId();

        StrategyCatalog catalog = strategyCatalogService.get(catalogId);

        strategy.setDestId(catalog.getDestId());
        //  目的地name
        strategy.setDestName(catalog.getDestName());

        // 主题名称
        StrategyTheme theme = strategyThemeService.get(strategy.getThemeId());
        strategy.setThemeName(theme.getName());

        // 分类名称
        strategy.setCatalogName(catalog.getName());

        //是否为国外
        // 用吐司得到的结果排序:中国-->广东-->广州
        List<Destination> toasts = destinationService.queryDesByParentId(catalog.getDestId());

        if (toasts != null && toasts.size() > 0) {
            // 获取集合中索引为0的中国
            Destination dest = toasts.get(0);
            if ("中国".equals(dest.getName())) {
                strategy.setIsabroad(Strategy.ABROAD_YES); // 国内
            } else {
                strategy.setIsabroad(Strategy.ABROAD_NO); // 国外
            }
        }
        if (StringUtils.hasLength(strategy.getId())){
            // 当进行编辑操作时,需要对部分冗余字段进行设值,因为页面传过来的对象数据中是不存在的,如果不设值,数据库表中的字段会消失;
            // 做添加操作时则不用,如没设值,默认为null.
            // 先查询对应攻略对象在数据库中的数据
            Strategy oldStrategy = this.get(strategy.getId());
            // 替换
            strategy.setViewnum(oldStrategy.getViewnum());
            strategy.setReplynum(oldStrategy.getReplynum());
            strategy.setFavornum(oldStrategy.getFavornum());
            strategy.setSharenum(oldStrategy.getSharenum());
            strategy.setThemeName(oldStrategy.getThemeName());
            // 更新
            this.update(strategy);
        }else {
            // 创建时间用于记录发布时间
            strategy.setCreateTime(new Date());
            this.add(strategy);
        }
    }


}
